{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import panel as pn\n",
    "import param\n",
    "\n",
    "pn.extension('codeeditor')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The ``CodeEditor`` widget allows embedding a code editor based on [Ace](https://ace.c9.io/).\n",
    "\n",
    "Only a small subset of Ace functionality is currently enabled:\n",
    "\n",
    " - **syntax highlighting** for several languages\n",
    " - **themes**\n",
    " - basic **completion** support via `ctrl+space` (using only static analysis of the code)\n",
    " - **annotations**\n",
    " - **readonly** mode\n",
    "\n",
    "#### Parameters:\n",
    "\n",
    "For details on other options for customizing the component see the [layout](../../how_to/layout/index.md) and [styling](../../how_to/styling/index.md) how-to guides.\n",
    "\n",
    "* **``annotations``** (list): list of annotations. An annotation is a dict with the following keys:\n",
    "    - `'row'`: row in the editor of the annotation\n",
    "    - `'column'`: column of the annotation\n",
    "    - `'text'`: text displayed when hovering over the annotation\n",
    "    - `'type'`: type of annotation and the icon displayed {`warning` | `error`}\n",
    "* **``filename``** (str): If filename is provided the file extension will be used to determine the language\n",
    "* **``indent``** (int): Number of spaces to use for default indentation.\n",
    "* **``language``** (str): A string declaring which language to use for code syntax highlighting (default: 'text')\n",
    "* **``on_keyup``** (bool): Whether to update the value on every key press or only upon loss of focus / hotkeys.\n",
    "* **``print_margin``** (boolean): Whether to show a print margin in the editor\n",
    "* **``soft_tabs``** (boolean): Whether to use spaces instead of tabs for indentation.\n",
    "* **``theme``** (str): If no value is provided, it defaults to the current theme set by pn.config.theme, as specified in the CodeEditor.THEME_CONFIGURATION dictionary. If not defined there, it falls back to the default parameter value ('chrome').\n",
    "* **``readonly``** (boolean): Whether the editor should be opened in read-only mode\n",
    "* **``value``** (str): State of the current code in the editor if `on_keyup`. Otherwise, only upon loss of focus, i.e. clicking outside the editor, or pressing <Ctrl+Enter> or <Cmd+Enter>.\n",
    "* **``value_input``** (str): State of the current code updated on every key press. Identical to `value` if `on_keyup`.\n",
    "___"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To construct an `Ace` widget we must define it explicitly using `pn.widgets.Ace`. We can add some text as initial code.\n",
    "Code inserted in the editor is automatically reflected in the `value_input` and `value`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "py_code = \"import sys\"\n",
    "editor = pn.widgets.CodeEditor(value=py_code, sizing_mode='stretch_width', language='python', height=300)\n",
    "editor"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "we can add some code in it"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "editor.value += \"\"\"\n",
    "import Math\n",
    "\n",
    "x = Math.cos(x)**2 + Math.cos(y)**2\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, the code editor will update the `value` on every key press, but you can set `on_keyup=False` to only update the `value` when the editor loses focus or pressing `<Ctrl+Enter>`/ `<Cmd+Enter>`. Here, the code is printed when `value` is changed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_code(value):\n",
    "    print(value)\n",
    "\n",
    "editor = pn.widgets.CodeEditor(value=py_code, on_keyup=False)\n",
    "pn.bind(print_code, editor.param.value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can change language and theme of the editor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "html_code = r\"\"\"<!DOCTYPE html>\n",
    "<html>\n",
    "    <head>\n",
    "        <meta http-equiv=\"content-type\" content=\"text/html; charset=utf-8\" />\n",
    "        <title>`substitute(Filename('', 'Page Title'), '^.', '\\u&', '')`</title>\n",
    "    </head>\n",
    "    <body>\n",
    "        <h1>Title1</h1>\n",
    "        <h2>Title2</h2>\n",
    "        <p>Paragraph</p>\n",
    "    </body>\n",
    "</html>\n",
    "\"\"\"\n",
    "editor.language = \"html\"\n",
    "editor.theme = \"monokai\"\n",
    "editor.value = html_code"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can add some annotations to the editor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "editor.annotations = [\n",
    "    dict(row=1, column=0, text='an error', type='error'),\n",
    "    dict(row=2, column=0, text='a warning', type='warning')\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we want just to display editor content but not edit it we can set the `readonly` property to `True`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#editor.readonly = True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If instead of setting the language explicitly we want to set the filename and automatically detect the language based on the file extension we can do that too:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "editor.filename = 'test.html'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Including the CodeEditor editor in a parameterized class\n",
    "\n",
    "You can view the Ace widget as part of a `param.Parameterized` class:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from panel.viewable import Viewer\n",
    "\n",
    "class CodeEditorTest(Viewer):\n",
    "    \n",
    "    editor = param.String('Hello World')\n",
    "    \n",
    "    def __panel__(self):\n",
    "        \"\"\" Map the string to appear as an Ace editor. \"\"\"\n",
    "        return pn.Param(\n",
    "            self.param,\n",
    "            widgets=dict(\n",
    "                editor=dict(\n",
    "                    type=pn.widgets.CodeEditor,\n",
    "                    language='python',\n",
    "                )\n",
    "            )\n",
    "        )\n",
    "    \n",
    "edit = CodeEditorTest()\n",
    "\n",
    "edit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Controls\n",
    "\n",
    "The `CodeEditor` widget exposes a number of options which can be changed from both Python and Javascript. Try out the effect of these parameters interactively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "widget = pn.widgets.CodeEditor(name='CodeEditor', value=py_code, language='python', sizing_mode='stretch_both', min_height=300)\n",
    "\n",
    "pn.Row(widget.controls(jslink=True), widget, sizing_mode='stretch_both')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try changing the filename including a file extension and watch the language automatically update."
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
